#include "pytool.hpp"
#include "ControlProxy.hpp"


namespace kuai { namespace suan {


	bool MolecularDynamicControlProxy::prepare(PyObject* self, PyObject* model, EnergySet& efunc, MolecularDynamicControl& result) {
		boost::tuple<PyObject*, kuai::XYZ*, size_t> coords = getXYZArray(model, "coords");
		if (boost::get<0>(coords) == NULL) {
			return false;
		}
		else {
			result.coords = boost::get<1>(coords);
			Py_DECREF(boost::get<0>(coords));
		}

		boost::tuple<PyObject*, kuai::RealNumber*, size_t> masses = getRealArray(model, "masses");
		if (boost::get<0>(masses) == NULL) {
			return false;
		}
		else {
			result.masses = boost::get<1>(masses);
			Py_DECREF(boost::get<0>(masses));
		}

		boost::tuple<PyObject*, kuai::XYZ*, size_t> speeds = getXYZArray(model, "speeds");
		if (boost::get<0>(speeds) == NULL) {
			return false;
		}
		else {
			result.speeds = boost::get<1>(speeds);
			Py_DECREF(boost::get<0>(speeds));
		}

		boost::tuple<PyObject*, kuai::XYZ*, size_t> grediants = getXYZArray(model, "grediants");
		if (boost::get<0>(grediants) == NULL) {
			return false;
		}
		else {
			result.grediants = boost::get<1>(grediants);
			Py_DECREF(boost::get<0>(grediants));
		}

		boost::tuple<PyObject*, kuai::RealNumber*, size_t> energies = getRealArray(model, "potential_e");
		if (boost::get<0>(energies) == NULL) {
			return false;
		}
		else {
			result.energies = boost::get<1>(energies);
			Py_DECREF(boost::get<0>(energies));
		}

		return true;
	}


	PythonControl::PythonControl(PyObject* self0, PyObject* model0, size_t period0) {
		self = self0;
		model = model0;
		period = period0;
	}
	
	void PythonControl::start(SimulationEnvironment& env, EnergySet& eset) {
		static PyObject* method = PyString_FromString("start");
		if (env.isMainThread()) {
			if (PyObject_HasAttr(self, method)) {
				PyObject* result = PyObject_CallMethodObjArgs(self, method, model, NULL);
				if (result != NULL) {
					Py_DECREF(result);
				}
				else {
					env.stop(true);
				}
			}
		}
		env.wait();
	}

	void PythonControl::act(SimulationEnvironment& env, EnergySet& eset, size_t istep) {
		static PyObject* method = PyString_FromString("act");
		if (env.isMainThread()) {
			if (PyObject_HasAttr(self, method)) {
				PyObject* step = PyInt_FromSize_t(istep);
				PyObject* result = PyObject_CallMethodObjArgs(self, method, model, step, NULL);
				Py_DECREF(step);
				if (result != NULL) {
					Py_DECREF(result);
				}
				else {
					env.stop(true);
				}
			}
		}
		env.wait();
	}
	
	void PythonControl::finish(SimulationEnvironment& env, EnergySet& eset, size_t nstep) {
		static PyObject* method = PyString_FromString("finish");
		if (env.isMainThread()) {
			if (PyObject_HasAttr(self, method)) {
				PyObject* step = PyInt_FromSize_t(nstep);
				PyObject* result = PyObject_CallMethodObjArgs(self, method, model, step, NULL);
				Py_DECREF(step);
				if (result != NULL) {
					Py_DECREF(result);
				}
				else {
					env.stop(true);
				}
			}
		}
		env.wait();
	}
	
	void PythonControl::finalize(SimulationEnvironment& env, EnergySet& eset) {
		if (env.isMainThread()) {
		}
		env.wait();
	};
	
} }
